home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / role / larn.lha / io.c < prev    next >
C/C++ Source or Header  |  1995-11-19  |  33KB  |  1,194 lines

  1. /* io.c
  2.  *
  3.  *  setupvt100()    Subroutine to set up terminal in correct mode for game
  4.  *  clearvt100()    Subroutine to clean up terminal when the game is over
  5.  *  ttgetch()       Routine to read in one character from the terminal
  6.  *  scbr()          Function to set cbreak -echo for the terminal
  7.  *  sncbr()         Function to set -cbreak echo for the terminal
  8.  *  newgame()       Subroutine to save the initial time and seed rnd()
  9.  *
  10.  *  FILE OUTPUT ROUTINES
  11.  *
  12.  *  lprintf(format,args . . .)  printf to the output buffer
  13.  *  lprint(integer)         send binary integer to output buffer
  14.  *  lwrite(buf,len)         write a buffer to the output buffer
  15.  *  lprcat(str)         sent string to output buffer
  16.  *
  17.  *  FILE OUTPUT MACROS (in header.h)
  18.  *
  19.  *  lprc(character)         put the character into the output buffer
  20.  *
  21.  *  FILE INPUT ROUTINES
  22.  *
  23.  *  long lgetc()            read one character from input buffer
  24.  *  long lrint()            read one integer from input buffer
  25.  *  lrfill(address,number)      put input bytes into a buffer
  26.  *  char *lgetw()           get a whitespace ended word from input
  27.  *  char *lgetl()           get a \n or EOF ended line from input
  28.  *
  29.  *  FILE OPEN / CLOSE ROUTINES
  30.  *
  31.  *  lcreat(filename)        create a new file for write
  32.  *  lopen(filename)         open a file for read
  33.  *  lappend(filename)       open for append to an existing file
  34.  *  lrclose()           close the input file
  35.  *  lwclose()           close output file
  36.  *  lflush()            flush the output buffer
  37.  *
  38.  *  Other Routines
  39.  *
  40.  *  cursor(x,y)     position cursor at [x,y]
  41.  *  cursors()       position cursor at [1,24] (saves memory)
  42.  *  cl_line(x,y)            Clear line at [1,y] and leave cursor at [x,y]
  43.  *  cl_up(x,y)          Clear screen from [x,1] to current line.
  44.  *  cl_dn(x,y)      Clear screen from [1,y] to end of display. 
  45.  *  standout(str)       Print the string in standout mode.
  46.  *  set_score_output()  Called when output should be literally printed.
  47.  ** ttputch(ch)     Print one character in decoded output buffer.
  48.  ** flush_buf()     Flush buffer with decoded output.
  49.  ** init_term()     Terminal initialization -- setup termcap info
  50.  ** char *tmcapcnv(sd,ss)   Routine to convert VT100 \33's to termcap format
  51.  *  beep()          Routine to emit a beep if enabled (see no-beep in .larnopts)
  52.  *
  53.  * Note: ** entries are available only in termcap mode.
  54.  */
  55.  
  56. #include "header.h"
  57. #include "larndefs.h"
  58. #include <ctype.h>
  59. #ifdef AMIGA
  60. #include <fcntl.h>
  61. #endif /* AMIGA */
  62.  
  63. #ifdef SYSV /* system III or system V */
  64. # ifndef MSDOS
  65. #   include <termio.h>
  66. # endif
  67. #define sgttyb termio
  68. #define stty(_a,_b) ioctl(_a,TCSETA,_b)
  69. #define gtty(_a,_b) ioctl(_a,TCGETA,_b)
  70. #ifndef MSDOS
  71. static int rawflg = 0;
  72. static char saveeof,saveeol;
  73. #define doraw(_a) if(!rawflg){++rawflg;saveeof=_a.c_cc[VMIN];saveeol=_a.c_cc[VTIME];}\
  74.     _a.c_cc[VMIN]=1;_a.c_cc[VTIME]=1;_a.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL)
  75. #define unraw(_a) _a.c_cc[VMIN]=saveeof;_a.c_cc[VTIME]=saveeol;_a.c_lflag |= ICANON|ECHO|ECHOE|ECHOK|ECHONL
  76. #endif
  77. #else not SYSV
  78. #ifdef VMS
  79. #include    <descrip.h>
  80. #include    <ssdef.h>
  81. #include    <stsdef.h>
  82. #include    <iodef.h>
  83. #include    <ttdef.h>
  84. #include    <tt2def.h>
  85. #else VMS
  86. #ifndef BSD
  87. #define CBREAK RAW      /* V7 has no CBREAK */
  88. #endif
  89. #define doraw(_a) (_a.sg_flags |= CBREAK,_a.sg_flags &= ~ECHO)
  90. #define unraw(_a) (_a.sg_flags &= ~CBREAK,_a.sg_flags |= ECHO)
  91. #ifndef AMIGA
  92. #include <sgtty.h>
  93. #endif /* AMIGA */
  94. #endif not SYSV
  95. #endif VMS
  96.  
  97. #ifndef NOVARARGS   /* if we have varargs */
  98. #ifdef AMIGA
  99. #include <stdarg.h>
  100. #else
  101. #include <varargs.h>
  102. #endif AMIGA
  103. #else NOVARARGS /* if we don't have varargs */
  104. typedef char *va_list;
  105. #define va_dcl int va_alist;
  106. #define va_start(plist) plist = (char *) &va_alist
  107. #define va_end(plist)
  108. #define va_arg(plist,mode) ((mode *)(plist += sizeof(mode)))[-1]
  109. #endif NOVARARGS
  110.  
  111. #define LINBUFSIZE 128      /* size of the lgetw() and lgetl() buffer       */
  112. int lfd;            /*  output file numbers     */
  113. int fd;             /*  input file numbers      */
  114. # ifndef AMIGA
  115. # ifndef MSDOS
  116. # ifndef VMS
  117. static struct sgttyb ttx;   /* storage for the tty modes                    */
  118. # else
  119. int iochan;         /* storage for the tty channel  */
  120. int ttx[3];         /* storage for the tty modes    */
  121. int cbflag;         /* cbreak flag.  Set when SCBRd */
  122. # endif VMS
  123. # endif MSDOS
  124. # endif AMIGA
  125. static int ipoint=MAXIBUF,iepoint=MAXIBUF;  /*  input buffering pointers    */
  126. static char lgetwbuf[LINBUFSIZE];   /* get line (word) buffer               */
  127.  
  128. #ifdef MSDOS
  129. # include <setjmp.h>
  130.  extern jmp_buf save_jbuf;
  131.  extern int save_mode;
  132. #endif
  133.  
  134. # ifdef MSDOS
  135. # include <fcntl.h>     /* For O_BINARY */
  136. static int (*getchfn)();
  137. int getche(), kgetch();
  138. # endif
  139.  
  140. /*
  141.  *  setupvt100()        Subroutine to set up terminal in correct mode for game
  142.  *
  143.  *  Attributes off, clear screen, set scrolling region, set tty mode 
  144.  */
  145. setupvt100()
  146.     {
  147. #ifdef VMS
  148.     struct  dsc$descriptor  idsc;
  149.     register int        status;
  150.  
  151.     idsc.dsc$a_pointer = "SYS$COMMAND";
  152.     idsc.dsc$w_length  = strlen(idsc.dsc$a_pointer);
  153.     idsc.dsc$b_dtype   = DSC$K_DTYPE_T;
  154.     idsc.dsc$b_class   = DSC$K_CLASS_S;
  155.     status = SYS$ASSIGN(&idsc, &iochan, 0, 0);
  156.     if (status&STS$M_SUCCESS == 0)
  157.         exit(status);
  158. #endif
  159.     lprc(T_INIT);
  160.     clear();  setscroll();  scbr(); /* system("stty cbreak -echo"); */
  161. # ifdef MSDOS
  162.     setraw();
  163.     setcursor();
  164.  
  165.     /* Select normal ASCII and line drawing character sets.
  166.      */
  167.     if (DECRainbow)
  168.         lprcat("\033(B\033)0");
  169. # endif
  170.     }
  171.  
  172. /*
  173.  *  clearvt100()        Subroutine to clean up terminal when the game is over
  174.  *
  175.  *  Attributes off, clear screen, unset scrolling region, restore tty mode 
  176.  */
  177. clearvt100()
  178.     {
  179.     lprc(T_END);
  180.     resetscroll();  clear();  sncbr(); /* system("stty -cbreak echo"); */
  181. # ifdef MSDOS
  182.     unsetraw();
  183.     resetcursor();
  184. # endif
  185. #ifdef VMS
  186.     SYS$DASSGN(iochan);
  187. #endif
  188.     }
  189.  
  190. /*
  191.  *  ttgetch()       Routine to read in one character from the terminal
  192.  */
  193.  
  194. #ifdef VMS
  195.  
  196. ttgetch()
  197. {
  198. #define NIBUF   80      /* characters in the buffer.    */
  199.     static char ibuf[NIBUF];
  200.     static int  ibufi = 0;
  201.     static int  nibuf = 0;
  202.     int status;
  203.     int iosb[2];
  204.     int term[2];
  205.  
  206.     lflush();       /* be sure output buffer is flushed */
  207.     term[0] = 0;
  208.     term[1] = 0;
  209.     while (ibufi >= nibuf) {
  210.         if (cbflag) {
  211.         /* cbroken */
  212.             ibufi   = 0;
  213. /*
  214.             status = SYS$QIOW(0, iochan, IO$_READLBLK|IO$M_TIMED,
  215.                  iosb, 0, 0, ibuf, NIBUF, 0, term, 0, 0);
  216. */
  217.             status = SYS$QIOW(0, iochan, IO$_READLBLK,
  218.                  iosb, 0, 0, ibuf, 1, 0, term, 0, 0);
  219.         if (status != SS$_NORMAL)
  220.             continue;
  221.         status = iosb[0] & 0xFFFF;
  222.         if (status!=SS$_NORMAL && status!=SS$_TIMEOUT)
  223.             continue;
  224.         nibuf = (iosb[0]>>16) + (iosb[1]>>16);
  225.         if (nibuf == 0) 
  226.         {
  227.         status = SYS$QIOW(0, iochan, IO$_READLBLK,
  228.             iosb, 0, 0, ibuf, 1, 0, term, 0, 0);
  229.         if (status != SS$_NORMAL)
  230.             continue;
  231.         if ((iosb[0]&0xFFFF) != SS$_NORMAL)
  232.             continue;
  233.         nibuf = (iosb[0]>>16) + (iosb[1]>>16);
  234.         }
  235.         } else {
  236.         /* not cbroken */
  237.         try_again:
  238.             ibufi    = 0;
  239.             status   = SYS$QIOW(0, iochan, IO$_READLBLK, iosb,
  240.                     0, 0, ibuf, NIBUF, 0, 0, 0, 0);
  241.             if (status != SS$_NORMAL)
  242.                 goto try_again;
  243.             if ((iosb[0]&0xFFFF) != SS$_NORMAL)
  244.                 goto try_again;
  245.             nibuf = (iosb[0]>>16) + (iosb[1]>>16);
  246.         }
  247.     }
  248.     if ((ibuf[ibufi]&0xFF) == '\r')     /* carriage return */
  249.         ibuf[ibufi] = '\n';     /* turns to newline */
  250.     return (ibuf[ibufi++]&0xFF);
  251. }
  252. #else VMS
  253.  
  254. ttgetch()
  255.     {
  256.     char byt;
  257. #ifdef EXTRA
  258.     c[BYTESIN]++;
  259. #endif EXTRA
  260.     lflush();       /* be sure output buffer is flushed */
  261.  
  262. # ifdef AMIGA
  263.     if((byt = AmGetch()) == '\r')
  264.         byt = '\n';
  265.     return byt;
  266. # endif AMIGA
  267. # ifdef MSDOS
  268.     if ((byt = (*getchfn)()) == '\r')
  269.         byt = '\n';
  270.     return byt;
  271. # else MSDOS
  272.     read(0,&byt,1);     /* get byte from terminal */
  273.     return(byt);
  274. # endif MSDOS
  275.     }
  276. # endif VMS
  277.  
  278. /*
  279.  *  scbr()      Function to set cbreak -echo for the terminal
  280.  *
  281.  *  like: system("stty cbreak -echo")
  282.  */
  283. scbr()
  284.     {
  285. # ifdef AMIGA
  286.     /* turn echo off */
  287.       AmCBreak(TRUE);
  288.       AmEcho(FALSE);
  289. # else
  290. # ifdef MSDOS
  291.     /* Set up to use the direct console input call which may
  292.      * read from the keypad;
  293.      */
  294.     getchfn = kgetch;
  295. # else
  296. # ifdef VMS
  297.     int status;
  298.     int iosb[2];
  299.  
  300.     cbflag = 1;
  301.     status = SYS$QIOW(0, iochan, IO$_SENSEMODE, iosb, 0, 0,
  302.               ttx, sizeof(ttx), 0, 0, 0, 0);
  303.     if (status&STS$M_SUCCESS == 0)
  304.         exit(status);
  305.     ttx[1] |= TT$M_NOECHO;
  306.     ttx[2] |= TT2$M_PASTHRU;
  307.     status = SYS$QIOW(0, iochan, IO$_SETMODE, iosb, 0, 0,
  308.               ttx, sizeof(ttx), 0, 0, 0, 0);
  309.     if (status&STS$M_SUCCESS == 0)
  310.         exit(status);
  311. # else
  312.     gtty(0,&ttx);       doraw(ttx);     stty(0,&ttx);
  313. # endif VMS
  314. # endif MSDOS
  315. # endif AMIGA
  316.     }
  317.  
  318. /*
  319.  *  sncbr()     Function to set -cbreak echo for the terminal
  320.  *
  321.  *  like: system("stty -cbreak echo")
  322.  */
  323. sncbr()
  324.     {
  325. # ifdef AMIGA
  326.       AmCBreak(FALSE);
  327.       AmEcho(TRUE);
  328. # else
  329. # ifdef MSDOS
  330.     /* Set up to use the direct console input call with echo, getche()
  331.      */
  332.     getchfn = getche;
  333. # else
  334. # ifdef VMS
  335.     int status;
  336.     int iosb[2];
  337.     cbflag = 0;
  338.     status = SYS$QIOW(0, iochan, IO$_SENSEMODE, iosb, 0, 0,
  339.               ttx, sizeof(ttx), 0, 0, 0, 0);
  340.     if (status&STS$M_SUCCESS == 0)
  341.         exit(status);
  342.     ttx[1] &= ~TT$M_NOECHO;
  343.     ttx[2] &= ~TT2$M_PASTHRU;
  344.     status = SYS$QIOW(0, iochan, IO$_SETMODE, iosb, 0, 0,
  345.               ttx, sizeof(ttx), 0, 0, 0, 0);
  346.     if (status&STS$M_SUCCESS == 0)
  347.         exit(status);
  348. # else
  349.     gtty(0,&ttx);       unraw(ttx);     stty(0,&ttx);
  350. # endif VMS
  351. # endif MSDOS
  352. # endif AMIGA
  353.     }
  354.  
  355. /*
  356.  *  newgame()       Subroutine to save the initial time and seed rnd()
  357.  */
  358. newgame()
  359. {
  360.     register long *p,*pe;
  361.     for (p=c,pe=c+100; p<pe; *p++ =0);
  362.     time(&initialtime);
  363.     srand(initialtime);
  364.     lcreat((char*)0);   /* open buffering for output to terminal */
  365. }
  366.  
  367. /*
  368.  *  lprintf(format,args . . .)      printf to the output buffer
  369.  *      char *format;
  370.  *      ??? args . . .
  371.  *
  372.  *  Enter with the format string in "format", as per printf() usage
  373.  *      and any needed arguments following it
  374.  *  Note: lprintf() only supports %s, %c and %d, with width modifier and left
  375.  *      or right justification.
  376.  *  No correct checking for output buffer overflow is done, but flushes 
  377.  *      are done beforehand if needed.
  378.  *  Returns nothing of value.
  379.  */
  380. #ifdef lint
  381. /*VARARGS*/
  382. lprintf(str)
  383.     char *str;
  384.     {
  385.     char *str2;
  386.     str2 = str;
  387.     str = str2; /* to make lint happy */
  388.     }
  389. /*VARARGS*/
  390. sprintf(str)
  391.     char *str;
  392.     {
  393.     char *str2;
  394.     str2 = str;
  395.     str = str2; /* to make lint happy */
  396.     }
  397. #else lint
  398. /*VARARGS*/
  399. #ifdef AMIGA
  400. lprintf(char *fmt, ...)
  401.     {
  402. #else
  403. lprintf(va_alist)
  404. va_dcl
  405.     {
  406.     register char *fmt;
  407. #endif AMIGA
  408.     va_list ap; /* pointer for variable argument list */
  409.     register char *outb,*tmpb;
  410.     register long wide,left,cont,n;     /* data for lprintf */
  411.     char db[12];            /* %d buffer in lprintf */
  412.  
  413. #ifdef AMIGA
  414.     va_start(ap, fmt);    /* initialize the var args pointer */
  415. #else
  416.     va_start(ap);   /* initialize the var args pointer */
  417.     fmt = va_arg(ap, char *);   /* pointer to format string */
  418. #endif /* AMIGA */
  419.     if (lpnt >= lpend) lflush(); 
  420.     outb = lpnt;
  421.     for ( ; ; )
  422.         {
  423.         while (*fmt != '%')
  424.             if (*fmt) *outb++ = *fmt++;  else { lpnt=outb;  return; }
  425.         wide = 0;   left = 1;   cont=1;
  426.         while (cont)
  427.           switch(*(++fmt))
  428.             {
  429.             case 'd':   n = va_arg(ap, long);
  430.                         if (n<0) { n = -n;  *outb++ = '-';  if (wide) --wide; }
  431.                         tmpb = db+11;   *tmpb = (char)(n % 10 + '0');
  432.                         while (n>9)  *(--tmpb) = (char)((n /= 10) % 10 + '0');
  433.                         if (wide==0)  while (tmpb < db+12) *outb++ = *tmpb++;
  434.                         else
  435.                             {
  436.                             wide -= db-tmpb+12;
  437.                             if (left)  while (wide-- > 0) *outb++ = ' ';
  438.                             while (tmpb < db+12) *outb++ = *tmpb++;
  439.                             if (left==0)  while (wide-- > 0) *outb++ = ' ';
  440.                             }
  441.                         cont=0; break;
  442.  
  443.             case 's':   tmpb = va_arg(ap, char *);
  444.                         if (wide==0)  { while (*outb++ = *tmpb++);  --outb; } 
  445.                         else
  446.                             {
  447.                             n = wide - strlen(tmpb);
  448.                             if (left)  while (n-- > 0) *outb++ = ' ';
  449.                             while (*outb++ = *tmpb++);  --outb;
  450.                             if (left==0)  while (n-- > 0) *outb++ = ' ';
  451.                             }
  452.                         cont=0; break;
  453.  
  454.             case 'c':   *outb++ = va_arg(ap, int);  cont=0;  break;
  455.  
  456.             case '0':
  457.             case '1':
  458.             case '2':
  459.             case '3':
  460.             case '4':
  461.             case '5':
  462.             case '6':
  463.             case '7':
  464.             case '8':
  465.             case '9':   wide = 10*wide + *fmt - '0';    break;
  466.  
  467.             case '-':   left = 0;   break;
  468.  
  469.             default:    *outb++ = *fmt;  cont=0;    break;
  470.             };
  471.         fmt++;
  472.         }
  473.     va_end(ap);
  474.     }
  475. #endif lint
  476.  
  477. /*
  478.  *  lprint(long-integer)                send binary integer to output buffer
  479.  *      long integer;
  480.  *
  481.  *      +---------+---------+---------+---------+
  482.  *      |   high  |         |         |   low   |
  483.  *      |  order  |         |         |  order  |
  484.  *      |   byte  |         |         |   byte  |
  485.  *      +---------+---------+---------+---------+
  486.  *     31  ---  24 23 --- 16 15 ---  8 7  ---   0
  487.  *
  488.  *  The save order is low order first, to high order (4 bytes total)
  489.  *      and is written to be system independent.
  490.  *  No checking for output buffer overflow is done, but flushes if needed!
  491.  *  Returns nothing of value.
  492.  */
  493. lprint(x)
  494.     register long x;
  495.     {
  496.     if (lpnt >= lpend) lflush();
  497.     *lpnt++ =  255 & x;         *lpnt++ =  255 & (x>>8);
  498.     *lpnt++ =  255 & (x>>16);   *lpnt++ =  255 & (x>>24);
  499.     }
  500.  
  501. /*
  502.  *  lwrite(buf,len)         write a buffer to the output buffer
  503.  *      char *buf;
  504.  *      int len;
  505.  *  
  506.  *  Enter with the address and number of bytes to write out
  507.  *  Returns nothing of value
  508.  */
  509. lwrite(buf,len)
  510.     register char *buf;
  511.     int len;
  512.     {
  513.     register char *str;
  514.     register int num2;
  515.     if (len > 399)  /* don't copy data if can just write it */
  516.         {
  517. #ifdef EXTRA
  518.         c[BYTESOUT] += len;
  519. #endif
  520.  
  521. #ifndef VT100
  522.         for (str=buf;  len>0; --len)
  523.             lprc(*str++);
  524. #else VT100
  525.         lflush();
  526.         write(lfd,buf,len);
  527. #endif VT100
  528.         } 
  529.     else while (len)
  530.         {
  531.         if (lpnt >= lpend) lflush();    /* if buffer is full flush it   */
  532.         num2 = lpbuf+BUFBIG-lpnt;   /*  # bytes left in output buffer   */
  533.         if (num2 > len) num2=len;
  534.         str = lpnt;  len -= num2;
  535.         while (num2--)  *str++ = *buf++;    /* copy in the bytes */
  536.         lpnt = str;
  537.         }
  538.     }
  539.  
  540. /*
  541.  *  long lgetc()        Read one character from input buffer
  542.  *
  543.  *  Returns 0 if EOF, otherwise the character
  544.  */
  545. long lgetc()
  546.     {
  547.     register int i;
  548.  
  549.     if (ipoint != iepoint)  return(inbuffer[ipoint++]);
  550.     if (iepoint!=MAXIBUF)   return(0);
  551.     if ((i=vread(fd,inbuffer,MAXIBUF))<=0) {
  552.         if (i!=0)
  553.             write(1,"error reading from input file\n",30);
  554.     iepoint = ipoint = 0;
  555.     return(0);
  556.     }
  557.     ipoint=1;  iepoint=i;  return(*inbuffer);
  558. }
  559.  
  560. /*
  561.  *  long lrint()            Read one integer from input buffer
  562.  *
  563.  *      +---------+---------+---------+---------+
  564.  *      |   high  |         |         |   low   |
  565.  *      |  order  |         |         |  order  |
  566.  *      |   byte  |         |         |   byte  |
  567.  *      +---------+---------+---------+---------+
  568.  *     31  ---  24 23 --- 16 15 ---  8 7  ---   0
  569.  *
  570.  *  The save order is low order first, to high order (4 bytes total)
  571.  *  Returns the int read
  572.  */
  573. long lrint()
  574.     {
  575.     register unsigned long i;
  576.     i  = 255 & lgetc();             i |= (255 & lgetc()) << 8;
  577.     i |= (255 & lgetc()) << 16;     i |= (255 & lgetc()) << 24;
  578.     return(i);
  579.     }
  580.  
  581. /*
  582.  *  lrfill(address,number)          put input bytes into a buffer
  583.  *      char *address;
  584.  *      int number;
  585.  *
  586.  *  Reads "number" bytes into the buffer pointed to by "address".
  587.  *  Returns nothing of value
  588.  */
  589. lrfill(adr,num)
  590.     register char *adr;
  591.     int num;
  592.     {
  593.     register char *pnt;
  594.     register int num2;
  595.     while (num)
  596.         {
  597.         if (iepoint == ipoint)
  598.             {
  599.             if (num>5) /* fast way */
  600.                 {
  601.                 if (vread(fd,adr,num) != num)
  602.                     write(2,"error reading from input file\n",30);
  603.                 num=0;
  604.                 }
  605.             else { *adr++ = lgetc();  --num; }
  606.             }
  607.         else
  608.             {
  609.             num2 = iepoint-ipoint;  /*  # of bytes left in the buffer   */
  610.             if (num2 > num) num2=num;
  611.             pnt = inbuffer+ipoint;  num -= num2;  ipoint += num2;
  612.             while (num2--)  *adr++ = *pnt++;
  613.             }
  614.         }
  615.     }
  616.  
  617. /*
  618.  *  char *lgetw()           Get a whitespace ended word from input
  619.  *
  620.  *  Returns pointer to a buffer that contains word.  If EOF, returns a NULL
  621.  */
  622. char *lgetw()
  623.     {
  624.     register char *lgp,cc;
  625.     register int n=LINBUFSIZE,quote=0;
  626.     lgp = lgetwbuf;
  627.     do cc=lgetc();  while ((cc <= 32) && (cc > NULL));  /* eat whitespace */
  628.     for ( ; ; --n,cc=lgetc())
  629.         {
  630.         if ((cc==NULL) && (lgp==lgetwbuf))  return(NULL);   /* EOF */
  631.         if ((n<=1) || ((cc<=32) && (quote==0))) { *lgp=NULL; return(lgetwbuf); }
  632.         if (cc != '"') *lgp++ = cc;   else quote ^= 1;
  633.         }
  634.     }
  635.  
  636. /*
  637.  *  char *lgetl()       Function to read in a line ended by newline or EOF
  638.  *
  639.  *  Returns pointer to a buffer that contains the line.  If EOF, returns NULL
  640.  */
  641. char *lgetl()
  642. {
  643.     register int i=LINBUFSIZE,ch;
  644.     register char *str=lgetwbuf;
  645.     for ( ; ; --i) {
  646.         *str++ = ch = lgetc();
  647.         if (ch == 0) {
  648.             if (str == lgetwbuf+1)
  649.                 return(NULL);   /* EOF */
  650.         ot: *str = 0;
  651.             return(lgetwbuf);   /* line ended by EOF */
  652.         }
  653.         if ((ch=='\n') || (i<=1))
  654.             goto ot;        /* line ended by \n */
  655.     }
  656. }
  657.  
  658. /*
  659.  *  lcreat(filename)            Create a new file for write
  660.  *      char *filename;
  661.  *
  662.  *  lcreat((char*)0); means to the terminal
  663.  *  Returns -1 if error, otherwise the file descriptor opened.
  664.  */
  665. lcreat(str)
  666.     char *str;
  667.     {
  668.     lpnt = lpbuf;   lpend = lpbuf+BUFBIG;
  669.     if (str==NULL) return(lfd=1);
  670. #ifdef AMIGA
  671.     if ((lfd=creat(str,S_IWRITE|S_IREAD)) < 0) 
  672. #else
  673.     if ((lfd=creat(str,0644)) < 0) 
  674. #endif /* AMIGA */
  675.         {
  676.         lfd=1; lprintf("error creating file <%s>\n",str); lflush(); return(-1);
  677.         }
  678. # ifdef MSDOS
  679.     setmode(lfd, O_BINARY);
  680. # endif
  681.     return(lfd);
  682.     }
  683.  
  684. /*
  685.  *  lopen(filename)         Open a file for read
  686.  *      char *filename;
  687.  *
  688.  *  lopen(0) means from the terminal
  689.  *  Returns -1 if error, otherwise the file descriptor opened.
  690.  */
  691. lopen(str)
  692.     char *str;
  693.     {
  694.     ipoint = iepoint = MAXIBUF;
  695.     if (str==NULL) return(fd=0);
  696.     if ((fd=open(str,0)) < 0)
  697.         {
  698.         lwclose(); lfd=1; lpnt=lpbuf; return(-1);
  699.         }
  700. # ifdef MSDOS
  701.     setmode(fd, O_BINARY);
  702. # endif
  703.     return(fd);
  704.     }
  705.  
  706. /*
  707.  *  lappend(filename)       Open for append to an existing file
  708.  *      char *filename;
  709.  *
  710.  *  lappend(0) means to the terminal
  711.  *  Returns -1 if error, otherwise the file descriptor opened.
  712.  */
  713. lappend(str)
  714.     char *str;
  715.     {
  716.     lpnt = lpbuf;   lpend = lpbuf+BUFBIG;
  717.     if (str==NULL) return(lfd=1);
  718.     if ((lfd=open(str,2)) < 0)
  719.         {
  720.         lfd=1; return(-1);
  721.         }
  722. # ifdef MSDOS
  723.     setmode(lfd, O_BINARY);
  724. # endif
  725.     lseek(lfd,0L,2);    /* seek to end of file */
  726.     return(lfd);
  727.     }
  728.  
  729. /*
  730.  *  lrclose()                       close the input file
  731.  *
  732.  *  Returns nothing of value.
  733.  */
  734. lrclose()
  735.     {
  736.     if (fd > 0) close(fd);
  737.     }
  738.  
  739. /*
  740.  *  lwclose()                       close output file flushing if needed
  741.  *
  742.  *  Returns nothing of value.
  743.  */
  744. lwclose()
  745.     {
  746.     lflush();   if (lfd > 2) close(lfd);
  747.     }
  748.  
  749. /*
  750.  *  lprcat(string)                  append a string to the output buffer
  751.  *                                  avoids calls to lprintf (time consuming)
  752.  */
  753. lprcat(str)
  754.     register char *str;
  755.     {
  756.     register char *str2;
  757.     if (lpnt >= lpend) lflush(); 
  758.     str2 = lpnt;
  759.     while (*str2++ = *str++);
  760.     lpnt = str2 - 1;
  761.     }
  762.  
  763. #ifdef VT100
  764. /*
  765.  *  cursor(x,y)         Subroutine to set the cursor position
  766.  *
  767.  *  x and y are the cursor coordinates, and lpbuff is the output buffer where
  768.  *  escape sequence will be placed. 
  769.  */
  770. static char *y_num[]= { "\33[","\33[","\33[2","\33[3","\33[4","\33[5","\33[6",
  771.     "\33[7","\33[8","\33[9","\33[10","\33[11","\33[12","\33[13","\33[14",
  772.     "\33[15","\33[16","\33[17","\33[18","\33[19","\33[20","\33[21","\33[22",
  773.     "\33[23","\33[24" };
  774.  
  775. static char *x_num[]= { "H","H",";2H",";3H",";4H",";5H",";6H",";7H",";8H",";9H",
  776.     ";10H",";11H",";12H",";13H",";14H",";15H",";16H",";17H",";18H",";19H",
  777.     ";20H",";21H",";22H",";23H",";24H",";25H",";26H",";27H",";28H",";29H",
  778.     ";30H",";31H",";32H",";33H",";34H",";35H",";36H",";37H",";38H",";39H",
  779.     ";40H",";41H",";42H",";43H",";44H",";45H",";46H",";47H",";48H",";49H",
  780.     ";50H",";51H",";52H",";53H",";54H",";55H",";56H",";57H",";58H",";59H",
  781.     ";60H",";61H",";62H",";63H",";64H",";65H",";66H",";67H",";68H",";69H",
  782.     ";70H",";71H",";72H",";73H",";74H",";75H",";76H",";77H",";78H",";79H",
  783.     ";80H" };
  784.  
  785. cursor(x,y)
  786.     int x,y;
  787.     {
  788.     register char *p;
  789.     if (lpnt >= lpend) lflush();
  790.  
  791.     p = y_num[y];   /* get the string to print */
  792.     while (*p) *lpnt++ = *p++;  /* print the string */
  793.  
  794.     p = x_num[x];   /* get the string to print */
  795.     while (*p) *lpnt++ = *p++;  /* print the string */
  796.     }
  797. #else VT100
  798. /*
  799.  * cursor(x,y)    Put cursor at specified coordinates staring at [1,1] (termcap)
  800.  */
  801. cursor (x,y)
  802.     int x,y;
  803.     {
  804.     if (lpnt >= lpend) lflush ();
  805.  
  806.     *lpnt++ = CURSOR;       *lpnt++ = x;        *lpnt++ = y;
  807.     }
  808. #endif VT100
  809.  
  810. /*
  811.  *  Routine to position cursor at beginning of 24th line
  812.  */
  813. cursors()
  814.     {
  815.     cursor(1,24);
  816.     }
  817.  
  818. #ifndef VT100
  819. /*
  820.  * Warning: ringing the bell is control code 7. Don't use in defines.
  821.  * Don't change the order of these defines.
  822.  * Also used in helpfiles. Codes used in helpfiles should be \E[1 to \E[7 with
  823.  * obvious meanings.
  824.  */
  825.  
  826. static char cap[256];
  827. static char *CM, *CE, *CD, *CL, *SO, *SE, *AL, *DL, *TI, *TE;/* Termcap capabilities */
  828. static char *outbuf=0;  /* translated output buffer */
  829.  
  830. static int ttputch ();
  831.  
  832. /*
  833.  * init_term()      Terminal initialization -- setup termcap info
  834.  */
  835. init_term()
  836.     {
  837.     char termbuf[1024];
  838.     char *capptr = cap+10;
  839.     char *term;
  840.  
  841. # ifdef MSDOS
  842.     term = getenv("TERM");
  843.     if (term == NULL)
  844.         term = "ibmpc-mono";
  845.     switch (tgetent(termbuf, term))
  846. # else
  847. # ifdef VMS
  848.     term = getenv("TERM");
  849.     if (term == NULL)
  850.         term = getenv("TERMINAL");
  851.     switch (tgetent(termbuf, term))
  852. # else
  853.     switch (tgetent(termbuf, term = getenv("TERM")))
  854. # endif
  855. # endif
  856.         {
  857.         case -1: 
  858.             write(2, "Cannot open termcap file.\n", 26); exit();
  859.         case 0: 
  860.             write(2, "Cannot find entry of ", 21);
  861.             write(2, term, strlen (term));
  862.             write(2, " in termcap\n", 12);
  863.             exit();
  864.         };
  865.  
  866.     CM = tgetstr("cm", &capptr);  /* Cursor motion */
  867.     CE = tgetstr("ce", &capptr);  /* Clear to eoln */
  868.     CL = tgetstr("cl", &capptr);  /* Clear screen */
  869.  
  870. /* OPTIONAL */
  871.     AL = tgetstr("al", &capptr);  /* Insert line */
  872.     DL = tgetstr("dl", &capptr);  /* Delete line */
  873.     SO = tgetstr("so", &capptr);  /* Begin standout mode */
  874.     SE = tgetstr("se", &capptr);  /* End standout mode */
  875.     CD = tgetstr("cd", &capptr);  /* Clear to end of display */
  876.     TI = tgetstr("ti", &capptr);  /* Terminal initialization */
  877.     TE = tgetstr("te", &capptr);  /* Terminal end */
  878.  
  879.     if (!CM)    /* can't find cursor motion entry */
  880.         {
  881.         write(2, "Sorry, for a ",13);       write(2, term, strlen(term));
  882.         write(2, ", I can't find the cursor motion entry in termcap\n",50);
  883.         exit();
  884.         }
  885.     if (!CE)    /* can't find clear to end of line entry */
  886.         {
  887.         write(2, "Sorry, for a ",13);       write(2, term, strlen(term));
  888.         write(2,", I can't find the clear to end of line entry in termcap\n",57);
  889.         exit();
  890.         }
  891.     if (!CL)    /* can't find clear entire screen entry */
  892.         {
  893.         write(2, "Sorry, for a ",13);       write(2, term, strlen(term));
  894.         write(2, ", I can't find the clear entire screen entry in termcap\n",56);
  895.         exit();
  896.         }
  897.     if ((outbuf=(char *)malloc(BUFBIG+16))==0) /* get memory for decoded output buffer*/
  898.         {
  899.         write(2,"Error malloc'ing memory for decoded output buffer\n",50);
  900.         died(-285); /* malloc() failure */
  901.         }
  902.     }
  903. #endif VT100
  904.  
  905. /*
  906.  * cl_line(x,y)  Clear the whole line indicated by 'y' and leave cursor at [x,y]
  907.  */
  908. cl_line(x,y)
  909.     int x,y;
  910.     {
  911. #ifdef VT100
  912.     cursor(x,y);        lprcat("\33[2K");
  913. #else VT100
  914.     cursor(1,y);        *lpnt++ = CL_LINE;      cursor(x,y);
  915. #endif VT100
  916.     }
  917.  
  918. /*
  919.  * cl_up(x,y) Clear screen from [x,1] to current position. Leave cursor at [x,y]
  920.  */
  921. cl_up(x,y)
  922.     register int x,y;
  923.     {
  924. #ifdef VT100
  925.     cursor(x,y);  lprcat("\33[1J\33[2K");
  926. #else VT100
  927.     register int i;
  928.     cursor(1,1);
  929.     for (i=1; i<=y; i++)   { *lpnt++ = CL_LINE;  *lpnt++ = '\n'; }
  930.     cursor(x,y);
  931. #endif VT100
  932.     }
  933.  
  934. /*
  935.  * cl_dn(x,y)   Clear screen from [1,y] to end of display. Leave cursor at [x,y]
  936.  */
  937. cl_dn(x,y)
  938.     register int x,y;
  939.     {
  940. #ifdef VT100
  941.     cursor(x,y); lprcat("\33[J\33[2K");
  942. #else VT100
  943.     register int i;
  944.     cursor(1,y);
  945.     if (!CD)
  946.         {
  947.         *lpnt++ = CL_LINE;
  948.         for (i=y; i<=24; i++) { *lpnt++ = CL_LINE;  if (i!=24) *lpnt++ = '\n'; }
  949.         cursor(x,y);
  950.         }
  951.     else
  952.         *lpnt++ = CL_DOWN;
  953.     cursor(x,y);
  954. #endif VT100
  955.     }
  956.  
  957. /*
  958.  * standout(str)    Print the argument string in inverse video (standout mode).
  959.  */
  960. standout(str)
  961.     register char *str;
  962.     {
  963. #ifdef VT100
  964.     setbold();
  965.     while (*str)
  966.         *lpnt++ = *str++;
  967.     resetbold();
  968. #else VT100
  969.     *lpnt++ = ST_START;
  970.     while (*str)
  971.         *lpnt++ = *str++;
  972.     *lpnt++ = ST_END;
  973. #endif VT100
  974.     }
  975.  
  976. /*
  977.  * set_score_output()   Called when output should be literally printed.
  978.  */
  979. set_score_output()
  980.     {
  981.     enable_scroll = -1;
  982.     }
  983.  
  984. /*
  985.  *  lflush()                        Flush the output buffer
  986.  *
  987.  *  Returns nothing of value.
  988.  *  for termcap version: Flush output in output buffer according to output
  989.  *                       status as indicated by `enable_scroll'
  990.  */
  991. #ifndef VT100
  992. static int scrline=18; /* line # for wraparound instead of scrolling if no DL */
  993. lflush ()
  994.     {
  995.     register int lpoint;
  996.     register char *str;
  997.     static int curx = 0;
  998.     static int cury = 0;
  999.  
  1000.     if ((lpoint = lpnt - lpbuf) > 0)
  1001.         {
  1002. #ifdef EXTRA
  1003.         c[BYTESOUT] += lpoint;
  1004. #endif
  1005.         if (enable_scroll <= -1) {
  1006.             flush_buf();
  1007. # ifdef MSDOS
  1008.             /* Catch write errors on save files
  1009.              */
  1010.                 if (write(lfd,lpbuf,lpoint) != lpoint) {
  1011.                     if (save_mode)
  1012.                         longjmp(save_jbuf, -1);
  1013.                     else
  1014.                         warn("Error writing output file\n");
  1015.                 }
  1016. # else
  1017. # ifdef AMIGA
  1018.         if(lfd == 1)
  1019.           WriteConsole(lpbuf, lpoint);
  1020.         else
  1021.           if(write(lfd,lpbuf,lpoint) != lpoint)
  1022.         write(2,"error writing to output file\n",29);
  1023. # else       
  1024.         if (write(lfd,lpbuf,lpoint) != lpoint)
  1025.           write(2,"error writing to output file\n",29);
  1026. # endif /* AMIGA */
  1027. # endif
  1028.             lpnt = lpbuf;   /* point back to beginning of buffer */
  1029.             return;
  1030.         }
  1031.         for (str = lpbuf; str < lpnt; str++)
  1032.             {
  1033.             if (*str>=32)   { ttputch (*str); curx++; }
  1034.             else switch (*str) {
  1035.                 case CLEAR:     tputs (CL, 1, ttputch);     curx = cury = 0;
  1036.                                 break;
  1037.  
  1038.                 case CL_LINE:   tputs (CE, 1, ttputch);
  1039.                                 break;
  1040.  
  1041.                 case CL_DOWN:   tputs (CD, 1, ttputch);
  1042.                                 break;
  1043.  
  1044.                 case ST_START:  tputs (SO, 1, ttputch);
  1045.                                 break;
  1046.  
  1047.                 case ST_END:    tputs (SE, 1, ttputch);
  1048.                                 break;
  1049.  
  1050.                 case CURSOR:    curx = *++str - 1;      cury = *++str - 1;
  1051.                                 tputs (tgoto (CM, curx, cury), 1, ttputch);
  1052.                                 break;
  1053.  
  1054.                 case '\n':      if ((cury == 23) && enable_scroll)
  1055.                                   {
  1056.                                   if (!DL || !AL) /* wraparound or scroll? */
  1057.                                     {
  1058.                                     if (++scrline > 23) scrline=19;
  1059.  
  1060.                                     if (++scrline > 23) scrline=19;
  1061.                                     tputs (tgoto (CM, 0, scrline), 1, ttputch);
  1062.                                     tputs (CE, 1, ttputch);
  1063.  
  1064.                                     if (--scrline < 19) scrline=23;
  1065.                                     tputs (tgoto (CM, 0, scrline), 1, ttputch);
  1066.                                     tputs (CE, 1, ttputch);
  1067.                                     }
  1068.                                   else
  1069.                                     {
  1070.                                     tputs (tgoto (CM, 0, 19), 1, ttputch);
  1071.                                     tputs (DL, 1, ttputch);
  1072.                                     tputs (tgoto (CM, 0, 23), 1, ttputch);
  1073.                                 /*  tputs (AL, 1, ttputch); */
  1074.                                     }
  1075.                                   }
  1076.                                 else
  1077.                                   {
  1078.                                   ttputch ('\n');       cury++;
  1079.                                   }
  1080.                                 curx = 0;
  1081.                                 break;
  1082.                 case T_INIT:
  1083.                     if (TI)
  1084.                         tputs(TI, 1, ttputch);
  1085.                     break;
  1086.                 case T_END:
  1087.                     if (TE)
  1088.                         tputs(TE, 1, ttputch);
  1089.                     break;
  1090.                 default:
  1091.                     ttputch (*str);
  1092.                     curx++;
  1093.                 }
  1094.             }
  1095.         }
  1096.     lpnt = lpbuf;
  1097.     flush_buf();    /* flush real output buffer now */
  1098.     }
  1099. #else VT100
  1100. /*
  1101.  *  lflush()                        flush the output buffer
  1102.  *
  1103.  *  Returns nothing of value.
  1104.  */
  1105. lflush()
  1106.     {
  1107.     register int lpoint;
  1108.     if ((lpoint = lpnt - lpbuf) > 0)
  1109.         {
  1110. #ifdef EXTRA
  1111.         c[BYTESOUT] += lpoint;
  1112. #endif
  1113.         if (write(lfd,lpbuf,lpoint) != lpoint)
  1114.             write(2,"error writing to output file\n",29);
  1115.         }
  1116.     lpnt = lpbuf;   /* point back to beginning of buffer */
  1117.     }
  1118. #endif VT100
  1119.  
  1120. #ifndef VT100
  1121. static int index=0;
  1122. /*
  1123.  * ttputch(ch)      Print one character in decoded output buffer.
  1124.  */
  1125. static int ttputch(c)
  1126. int c;
  1127.     {
  1128.     outbuf[index++] = c;
  1129.     if (index >= BUFBIG)  flush_buf();
  1130.     }
  1131.  
  1132. /*
  1133.  * flush_buf()          Flush buffer with decoded output.
  1134.  */
  1135. static flush_buf()
  1136.     {
  1137. #ifdef AMIGA
  1138.       if(lfd == 1)
  1139.     WriteConsole(outbuf, index);
  1140.       else
  1141.     if(write(lfd,outbuf,index) != index)
  1142.       write(2,"error writing to output file\n",29);
  1143. #else
  1144.     if (index) write(lfd, outbuf, index);
  1145. #endif /* AMIGA */
  1146.     index = 0;
  1147.     }
  1148.  
  1149. /*
  1150.  *  char *tmcapcnv(sd,ss)  Routine to convert VT100 escapes to termcap format
  1151.  *
  1152.  *  Processes only the \33[#m sequence (converts . files for termcap use 
  1153.  */
  1154. char *tmcapcnv(sd,ss)  
  1155.     register char *sd,*ss;
  1156.     {
  1157.     register int tmstate=0; /* 0=normal, 1=\33 2=[ 3=# */
  1158.     char tmdigit=0; /* the # in \33[#m */
  1159.     while (*ss)
  1160.         {
  1161.         switch(tmstate)
  1162.             {
  1163.             case 0: if (*ss=='\33')  { tmstate++; break; }
  1164.               ign:  *sd++ = *ss;
  1165.               ign2: tmstate = 0;
  1166.                     break;
  1167.             case 1: if (*ss!='[') goto ign;
  1168.                     tmstate++;
  1169.                     break;
  1170.             case 2: if (isdigit(*ss)) { tmdigit= *ss-'0'; tmstate++; break; }
  1171.                     if (*ss == 'm') { *sd++ = ST_END; goto ign2; }
  1172.                     goto ign;
  1173.             case 3: if (*ss == 'm')
  1174.                         {
  1175.                         if (tmdigit) *sd++ = ST_START;
  1176.                             else *sd++ = ST_END;
  1177.                         goto ign2;
  1178.                         }
  1179.             default: goto ign;
  1180.             };
  1181.         ss++;
  1182.         }
  1183.     *sd=0; /* NULL terminator */
  1184.     return(sd);
  1185.     }
  1186. #endif VT100
  1187.  
  1188. /*
  1189.  *  beep()      Routine to emit a beep if enabled (see no-beep in .larnopts)
  1190.  */
  1191. beep() {
  1192.     if (!nobeep) *lpnt++ = '\7';
  1193.     }
  1194.